#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <cstring>
#include <signal.h>
#include <vector>
#include <functional>
#include <cassert>

using namespace std;

int count = 0;

void waitChild(int signum)
{
    // 在该信号捕捉函数内完成对子进程的回收
    while (true) // 循环回收，防止回收期间又有子进程退出,而未决信号集并不能记录收到信号数量，会导致子进程少回收
    {
        if (count == 10)
            break; // 子进程回收完毕

        int status = 0;
        int n = waitpid(-1, &status, WNOHANG); // 回收随机返回的进程
        assert(n != -1);

        if (n == 0) // 说明当前没子进程退出了
            break;

        if (n != 0) // n==退出子进程的pid
        {
            if (WIFEXITED(status)) // 正常退出，获取退出码
            {
                cout << "wait child: pid[" << n << "] exitCode[" << WEXITSTATUS(status) << "]" << endl;
            }
            else // 不正常退出，获取退出信号
            {
                cout << "wait child: pid[" << n << "] exitSignal[" << (status & 0x7F) << "]" << endl;
            }
            count++; // 加到10说明子进程回收完了
        }
    }
}

void childExit(int signum)
{
    if (getpid() % 3 == 0) // 设置一些收到信号而终止的子进程
    {
        int sig = rand() % 3 + 1;
        cout << "Child[" << getpid() << "] term by raise signal[" << sig << "]" << endl;
        raise(sig); // 随机1，2，3号信号退出
        exit(1);
    }

    int code = (rand() % 100) + 1; // 随机退出码
    cout << "Child[" << getpid() << "] exit[" << code << "]" << endl;
    exit(code);
}

// sigaction
int main()
{
    srand((unsigned long)time(NULL) ^ getpid() ^ 114514); // 每个进程都生成不同的随机数

    signal(SIGCHLD, waitChild); // 父进程绑定SIGCHLD信号

    // //系统默认忽略:子进程退出，直接忽略，不会自动回收
    // signal(SIGCHLD,SIG_IGN);
    // //手动设置忽略:告诉系统，不关心子进程退出信息，子进程退出就直接自动被回收

    for (int i = 0; i < 10; i++)
    {
        int id = fork();
        assert(id != -1);
        if (id == 0)
        {
            srand((unsigned long)time(NULL) ^ getpid() ^ 114514); // 每个进程都生成不同的随机数
            signal(SIGALRM, childExit);
            alarm((rand() % 10) + 1); // 子进程随机秒后退出
            while (true)
                sleep(1); // 卡住子进程，子进程只能被闹钟唤醒后退出
            exit(0);
        }
    }

    while (true)
    {
        cout << "father[" << getpid() << "]" << " is working" << endl; // 父进程一直在执行任务
        sleep(3); // 周期打印，但在信号的影响下会有差别                                                     
    }
    return 0;
}

// static void printPending(const sigset_t *pending)
// {
//     for (int i = 1; i <= 31; i++)
//     {
//         if (sigismember(pending, i))
//             cout << "1";
//         else
//             cout << "0";
//     }
//     cout << endl;
// }

// void setBlock(int sigNum) // 屏蔽单个信号
// {
//     sigset_t bset;
//     sigaddset(&bset, sigNum);
//     int n = sigprocmask(SIG_BLOCK, &bset, NULL);
//     assert(n == 0);
//     (void)n;
// }

// int main()
// {
//     for (int i = 1; i <= 31; i++)
//     {
//         setBlock(i); // 逐渐屏蔽所有信号
//         cout << i << ":";

//         // 屏蔽之后给自己发一个
//         if (i != SIGKILL && i != SIGSTOP)
//             raise(i);

//         sigset_t pending;
//         sigpending(&pending);
//         printPending(&pending); // 打印未决信号集
//         // sleep(1);
//     }
// }

// void catchiSig(int signum)
// {
//     cout<<"catch signal:"<<signum<<endl;
//     if(signum==SIGALRM)
//     {
//         sigset_t bset;
//         sigemptyset(&bset);
//         int n = sigprocmask(SIG_SETMASK, &bset, NULL);
//         //解除对SIGINT的阻塞后，立马就递达了
//         alarm(3);
//     }
// }

// int main()
// {
//     signal(SIGALRM, catchiSig);
//     signal(SIGINT,catchiSig);
//     alarm(3);

//     sigset_t bset, obset;
//     sigset_t pending;

//     sigemptyset(&bset);
//     sigemptyset(&obset); // 清空

//     sigaddset(&bset, 2); // 屏蔽SIGITNT信号

//     int n = sigprocmask(SIG_BLOCK, &bset, &obset); // 设置信号屏蔽字
//     assert(n == 0);                                // for debug
//     (void)n;                                       // for release

//     while (true)
//     {
//         sigpending(&pending);
//         printPending(&pending);
//         sleep(1);
//     }
//     return 0;
// }